/**
 * Utilities for working with Git repositories
 */
const vscode = require('vscode');
const simpleGit = require('simple-git');
const path = require('path');

/**
 * Gets commits from the current repository, optionally filtered by date range
 */
async function getCommits(startDate, endDate) {
  const workspaceFolders = vscode.workspace.workspaceFolders;
  if (!workspaceFolders || workspaceFolders.length === 0) {
    throw new Error("No workspace folder is open");
  }
  
  // Use the first workspace folder
  const repoPath = workspaceFolders[0].uri.fsPath;
  const git = simpleGit(repoPath);
  
  try {
    // Check if this is a git repository
    const isRepo = await git.checkIsRepo();
    if (!isRepo) {
      throw new Error("The current workspace is not a Git repository");
    }
    
    // Prepare options for log command
    let logOptions = {
      '--pretty': 'format:{"hash": "%H", "date": "%aI", "author": "%an", "email": "%ae", "message": "%s", "body": "%b"}'
    };
    
    // Add date filtering if provided
    if (startDate && endDate) {
      logOptions['--after'] = startDate.toISOString();
      logOptions['--before'] = endDate.toISOString();
    }
    
    // Get log output
    const logOutput = await git.log(logOptions);
    
    // Parse the JSON output
    const commits = logOutput.all.map(commit => ({
      hash: commit.hash,
      date: new Date(commit.date),
      author: commit.author,
      email: commit.email,
      message: commit.message,
      body: commit.body.trim()
    }));
    
    return commits;
  } catch (error) {
    console.error("Error fetching git commits:", error);
    throw new Error(`Failed to fetch git commits: ${error.message}`);
  }
}

/**
 * Analyzes commits to generate a summary
 */
async function analyzeCommits(commits) {
  // Group commits by common prefixes and related topics
  const featureGroups = groupCommitsByFeature(commits);
  
  // Categorize changes
  const categories = categorizeChanges(featureGroups);
  
  return {
    totalCommits: commits.length,
    authors: getUniqueAuthors(commits),
    timespan: getTimespan(commits),
    featureGroups,
    categories
  };
}

/**
 * Groups commits by feature based on related message content
 */
function groupCommitsByFeature(commits) {
  // This is a simplified algorithm - a real implementation would use NLP or more sophisticated grouping
  
  // First, extract prefixes like "feat:", "fix:", etc.
  const commitsByPrefix = {};
  
  commits.forEach(commit => {
    const message = commit.message;
    // Common prefixes in conventional commits
    const prefixMatch = message.match(/^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\([^)]+\))?:/i);
    
    if (prefixMatch) {
      const prefix = prefixMatch[0];
      if (!commitsByPrefix[prefix]) {
        commitsByPrefix[prefix] = [];
      }
      commitsByPrefix[prefix].push(commit);
    } else {
      // For commits without standard prefix, use the first word
      const firstWord = message.split(' ')[0];
      const key = `other:${firstWord}`;
      if (!commitsByPrefix[key]) {
        commitsByPrefix[key] = [];
      }
      commitsByPrefix[key].push(commit);
    }
  });
  
  // Convert to array format with titles
  return Object.entries(commitsByPrefix).map(([prefix, groupCommits]) => {
    return {
      title: formatFeatureTitle(prefix, groupCommits),
      commits: groupCommits
    };
  }).sort((a, b) => b.commits.length - a.commits.length); // Sort by number of commits
}

/**
 * Creates a human-readable title for a feature group
 */
function formatFeatureTitle(prefix, commits) {
  if (commits.length === 0) return prefix;
  
  if (prefix.startsWith("feat:")) {
    return `Feature: ${commonWordsBetweenCommits(commits)}`;
  } else if (prefix.startsWith("fix:")) {
    return `Fix: ${commonWordsBetweenCommits(commits)}`;
  } else if (prefix.startsWith("docs:")) {
    return `Documentation: ${commonWordsBetweenCommits(commits)}`;
  } else if (prefix.startsWith("refactor:")) {
    return `Refactoring: ${commonWordsBetweenCommits(commits)}`;
  } else if (prefix.startsWith("test:")) {
    return `Testing: ${commonWordsBetweenCommits(commits)}`;
  } else if (prefix.startsWith("chore:")) {
    return `Maintenance: ${commonWordsBetweenCommits(commits)}`;
  } else {
    return `${prefix} ${commonWordsBetweenCommits(commits)}`;
  }
}

/**
 * Finds common words between commit messages
 */
function commonWordsBetweenCommits(commits) {
  if (commits.length === 1) {
    // For a single commit, use the message (without the prefix)
    const message = commits[0].message;
    const withoutPrefix = message.includes(":") ? message.split(":", 2)[1].trim() : message;
    return withoutPrefix.length > 50 ? withoutPrefix.substring(0, 50) + "..." : withoutPrefix;
  }
  
  // Find common words in the first few commits
  const messages = commits.slice(0, 3).map(c => c.message);
  const words = messages.map(msg => 
    msg.toLowerCase()
      .replace(/[^\w\s]/g, '')
      .split(/\s+/)
      .filter(w => w.length > 3) // Filter out short words
  );
  
  // Find words that appear in multiple commits
  const wordCounts = {};
  words.flat().forEach(word => {
    wordCounts[word] = (wordCounts[word] || 0) + 1;
  });
  
  const commonWords = Object.entries(wordCounts)
    .filter(([word, count]) => count > 1)
    .map(([word]) => word)
    .slice(0, 5); // Take top 5 common words
  
  return commonWords.length > 0 
    ? commonWords.join(" ")
    : (commits[0].message.includes(":") 
        ? commits[0].message.split(":", 2)[1].trim()
        : commits[0].message); // Fallback to first message
}

/**
 * Categorizes commit groups into features, fixes, etc.
 */
function categorizeChanges(featureGroups) {
  const categories = {
    features: [],
    fixes: [],
    documentation: [],
    refactoring: [],
    other: []
  };
  
  featureGroups.forEach(group => {
    const title = group.title.toLowerCase();
    
    if (title.startsWith("feature:")) {
      categories.features.push(group);
    } else if (title.startsWith("fix:")) {
      categories.fixes.push(group);
    } else if (title.startsWith("documentation:")) {
      categories.documentation.push(group);
    } else if (title.startsWith("refactoring:")) {
      categories.refactoring.push(group);
    } else {
      categories.other.push(group);
    }
  });
  
  return categories;
}

/**
 * Gets a list of unique authors from commits
 */
function getUniqueAuthors(commits) {
  const authors = new Map();
  
  commits.forEach(commit => {
    if (!authors.has(commit.email)) {
      authors.set(commit.email, {
        name: commit.author,
        email: commit.email,
        commitCount: 1
      });
    } else {
      const author = authors.get(commit.email);
      author.commitCount++;
    }
  });
  
  return Array.from(authors.values());
}

/**
 * Gets the timespan of the commits
 */
function getTimespan(commits) {
  if (commits.length === 0) {
    return { start: null, end: null, days: 0 };
  }
  
  // Sort commits by date
  const sortedCommits = [...commits].sort((a, b) => a.date - b.date);
  
  const start = sortedCommits[0].date;
  const end = sortedCommits[sortedCommits.length - 1].date;
  const days = Math.round((end - start) / (1000 * 60 * 60 * 24));
  
  return { start, end, days };
}

module.exports = {
  getCommits,
  analyzeCommits
};
